# self指向
"""
在我们设计类方法的时候 self 通常是指向本身

但是这个时候如果一个类 被继承 了

那么继承这个子类, 在实例化后, 父类的self就是指向子类
"""

# class Parent():
#
#     def showName(self):
#         print(self.name)  # 实际上用的是子对象的name
#
#
# class Child(Parent):  # 继承方式就是在定义类的时候，在括号里写上需要继承的类
#
#     def __init__(self, name) -> None:
#         super().__init__()
#         self.name = name
#
#
# child = Child('muzhou')
#
# child.showName()  # 调用的父类的方法 --> 把父类的方法给了自己 --> 这个方法中的self就是自己

# 类初始化函数init

"""
可以注意到上面的例子, 我们在子类中编写 __init__时
会有 super().__init__() 它确实需要这个.
文字说起来可能不太直观, 我们来看代码.
"""

class Parent():

    def __init__(self, parentName) -> None:
        self.parentName = parentName

    def showParentName(self):
        print(self.parentName)


# class Child(Parent):  # 继承方式就是在定义类的时候，在括号里写上需要继承的类
#
#     def __init__(self, childName) -> None:
#         super().__init__(childName)
#         self.childName = childName
#
#
# child = Child('muzhou')
#
# child.showParentName()  # 调用的父类的方法 报错啦

"""
这个时候, showParentName 这个函数, 调用的是 self.parentName

这个 parentName 在子类中没有定义, 只有在父类中通过 init 来给予

所以我们在子类的 __init__ 中还需要单独调用 super().__init__()
"""

# class Parent():
#
#     def __init__(self, parentName) -> None:
#         self.parentName = parentName
#
#     def showParentName(self):
#         print(self.parentName)
#
#
# class Child(Parent):  # 继承方式就是在定义类的时候，在括号里写上需要继承的类
#
#     def __init__(self, parentName) -> None:
#         super().__init__(parentName)
#
#
# child = Child('muzhou')
#
# child.showParentName()  # 调用的父类的方法
#
#
# class Parent():
#
#     def __init__(self, parentName) -> None:
#         self.parentName = parentName
#
#     def showParentName(self):
#         print(self.parentName)
#
#
# class Child(Parent):  # 继承方式就是在定义类的时候，在括号里写上需要继承的类
#
#     def __init__(self, parentName, childName) -> None:
#         super().__init__(parentName)
#         self.childName = childName
#
#     def showMyName(self):
#         print(self.childName)
#
#
# child = Child('muzhouParent', 'muzhouChild')  # 因为child的 __init__ 用到了两个参数
#
# child.showParentName()  # 调用的父类的方法
# child.showMyName()  # 调用的子类的方法

# 继承可以迭代

"""
class Grand():
    ...

class Parent(Grand):
    ...

class Chlid(Parent):
    ...
"""

# 继承可以怎么玩

# class BWM():
#     brand = "BMW"
#
#     def func(self):
#         print("宝马都有的功能")
#
#     def face(self):
#         print("宝马都有的大鼻孔")
#
#
# class BWM5(BWM):
#     height = 1400
#     width = 4000
#     price = '20w'
#
#     def __init__(self, color) -> None:
#         super().__init__()
#         self.color = color
#
#     def func(self):
#         super().func()
#         print("BMW5特有的功能")
#
#
#
# class BWM7(BWM):
#     height = 2000
#     width = 6000
#     price = '30w'
#
#     def __init__(self, color) -> None:
#         super().__init__()
#         self.color = color
#
#     def func(self):
#         super().func()
#         print("BMW7特有的功能")
#
#
# bmw5 = BWM5('blue')
# bmw7 = BWM7('blue')
#
# print(f"我的牌子 {bmw5.brand}, 我的宽高 height: {bmw5.height} width: {bmw5.width}, 单价: {bmw5.price}")
# bmw5.func()
#
# print(f"我的牌子 {bmw7.brand}, 我的宽高 height: {bmw7.height} width: {bmw7.width}, 单价: {bmw7.price}")
# bmw7.func()
#
# bmw5.face()
# bmw7.face()

"""
总结就是:

封装一个基类, 这个基类具备基本且通用的信息, 以及一些功能
封装一个子类, 这个子类在父类的基础上进行拓展/重写
总之, 如何设计程序, 主要在于编码者的经验, 只要最后能达到想要的效果, 任何手段都是正确的, 只要确认自己每一次封装都比上一次更加得心应手且便于维护即可
"""

# 多继承

"""
之前展示的都是 单继承

实际上, 还可以进行多继承

顾名思义, 就是一个子类可以有两个 爸爸
"""
class Animal():  # 动物
    def eat(self):
        print("动物都会吃饭")


class WildAnimal():  # 野生动物
    def hunt(self):
        print("野生动物会捕猎")


class Pet():  # 宠物
    def play(self):
        print("和主人一块玩")


class HaDog(Animal, Pet):
    def info(self):
        print("不太聪明的样子")


class Wolf(Animal, WildAnimal):
    ...

哈狗 = HaDog()

哈狗.info()
哈狗.eat()
哈狗.play()